package jk.fox.spring.config;


import jk.fox.common.payload.message.MessageDispatcher;
import jk.fox.config.RpcConfiguration;
import jk.fox.config.RpcConfiguration.RpcConfigBuilder;
import jk.fox.engine.DefaultRpcEngine;
import jk.fox.engine.RpcEngine;
import jk.fox.engine.listener.RpcServiceStartedListener;
import jk.fox.engine.context.RpcContext;
import jk.fox.node.StandardMessageDispatcher;
import jk.fox.node.rule.RoundRobinRuleFactory;
import jk.fox.node.rule.RuleFactory;
import org.springframework.beans.factory.ObjectProvider;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.autoconfigure.condition.ConditionalOnBean;
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
import org.springframework.boot.context.properties.EnableConfigurationProperties;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;


/**
 * @author cuichao
 * @Description: SpringFoxConfig
 * @Date: create in 2020/5/28 16:51
 */
@ConditionalOnProperty(
        prefix = "fox.rpc",
        name = {"enabled"},
        matchIfMissing = true
)
@Configuration
@EnableConfigurationProperties(value = {FoxRpcConfigurationProperties.class})
public class FoxRpcAutoConfiguration {
    @Autowired
    private FoxRpcConfigurationProperties properties;



    @ConditionalOnMissingBean(RuleFactory.class)
    @Bean
    public RuleFactory ruleFactory(){
        return new RoundRobinRuleFactory();
    }
    @ConditionalOnMissingBean(MessageDispatcher.class)
    @Bean
    public MessageDispatcher messageDispatcher(){
        return new StandardMessageDispatcher();
    }

    @ConditionalOnBean({RuleFactory.class,MessageDispatcher.class})
    @ConditionalOnMissingBean(RpcConfiguration.class)
    @Bean
    public RpcConfiguration rpcConfigure(RuleFactory ruleFactory, MessageDispatcher dispatcher){
        RpcConfigBuilder builder = new RpcConfigBuilder();
        builder
                .expose(properties.getPort())
                .enableSameSource(properties.isEnableSameSource())
                .requestTimeOutMs(properties.getRequestTimeOutMs())
                .enableRequestRetry(properties.isEnableRequestRetry())
                .requestMaxRetires(properties.getRequestMaxRetires())
                .dispatcher(dispatcher)
                .ruleFactory(ruleFactory)
                .exchange()
                .connectMaxRetries(properties.getConnectMaxRetries())
                .connectRetryIntervalMS(properties.getConnectRetryIntervalMs());
        //config registry
        RegistryConfigurationProperties registry = properties.getRegistry();
        buildRegistryConfig(builder, registry);
        //config transport
        TransportConfigurationProperties transport = properties.getTransport();
        buildTransportConfig(builder,transport);
        //build
        RpcConfiguration rpcConfigure = builder.build();
        return rpcConfigure;
    }



    @ConditionalOnMissingBean(RpcEngine.class)
    @Bean
    public RpcEngine rpcEngine(
            RpcContext context,
            RpcConfiguration rpcConfigure,
            ObjectProvider<RpcServiceStartedListener> startedListeners
            ){

        DefaultRpcEngine engine = new DefaultRpcEngine(rpcConfigure, context);
        startedListeners.forEach( v -> engine.addRpcServiceStartedListener(v));
        return engine;
    }


    protected void buildRegistryConfig(RpcConfigBuilder builder, RegistryConfigurationProperties properties){
        switch (properties.getType()){
            case "zookeeper":
                buildZookeeperConfig(builder,properties.getZookeeper());
                return;
            default:
                buildZookeeperConfig(builder,properties.getZookeeper());
                return;
        }
    }

    protected void buildTransportConfig(RpcConfigBuilder builder, TransportConfigurationProperties properties){
        switch (properties.getType()){
            case "netty":
                buildNettyConfig(builder,properties.getNetty());
                return;
            default:
                buildNettyConfig(builder,properties.getNetty());
                return;
        }
    }



    protected void buildZookeeperConfig(RpcConfigBuilder builder,ZookeeperConfigurationProperties properties){
        builder
          .zookeeper()
                .address(properties.getAddress())
                .connectionTimeoutMs(properties.getConnectionTimeoutMs())
                .maxRetires(properties.getMaxRetires())
                .retryIntervalMs(properties.getRetryIntervalMs())
                .sessionTimeoutMs(properties.getSessionTimeoutMs());
    }

    protected void buildNettyConfig(RpcConfigBuilder builder,NettyConfigurationProperties properties){
        builder
          .netty()
                .serverWorkGroup(properties.getServerWorkGroup())
                .serverTcpBacklog(properties.getServerTcpBacklog())
                .serverHeartBeat(properties.getServerHeartBeat())
                .keepAlive(properties.isKeepAlive())
                .disableNagle(properties.isDisableNagle())
                .clientHeartBeat(properties.getClientHeartBeat());
    }

}
